//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Xml;
using OpenLS.Core.Serialization;

namespace OpenLS.Core
{
    class Variant: IOfficeXmlSerializable
    {
        public void ReadXml(ReadContext context)
        {
            using (var c = context.Read("variant"))
            {
                _item = ReadItem(c);
            }

        }

        private object _item;

        public void WriteXml(WriteContext context)
        {
            using (var c = context.Write("variant"))
            {
                WriteItem(_item, c);
            }
        }
        public static object ReadItem(ReadContext context)
        {
            switch (context.ReaderLocalName)
            {
                case "lpstr":
                    return context.ReadElementString(context.ReaderLocalName);

                case "i1":
                    return sbyte.Parse(context.ReadElementString(context.ReaderLocalName));
                case "i2":
                    return short.Parse(context.ReadElementString(context.ReaderLocalName));
                case "i4":
                    return int.Parse(context.ReadElementString(context.ReaderLocalName));
                case "i8":
                    return long.Parse(context.ReadElementString(context.ReaderLocalName));
                case "ui1":
                    return byte.Parse(context.ReadElementString(context.ReaderLocalName));
                case "ui2":
                    return ushort.Parse(context.ReadElementString(context.ReaderLocalName));
                case "ui4":
                    return uint.Parse(context.ReadElementString(context.ReaderLocalName));
                case "ui8":
                    return ulong.Parse(context.ReadElementString(context.ReaderLocalName));
                case "r4":
                    return float.Parse(context.ReadElementString(context.ReaderLocalName), CultureInfo.InvariantCulture);
                case "r8":
                    return double.Parse(context.ReadElementString(context.ReaderLocalName), CultureInfo.InvariantCulture);
                case "bool":
                    return bool.Parse(context.ReadElementString(context.ReaderLocalName));
                case "variant":
                    return context.ReadElement<Variant>();



                case "lpwstr":


                case "bstr":



                case "date":


                case "filetime":
                case "cy":



                case "error":



                case "clsid":



                case "cf":



                    throw new NotImplementedException();
                default: throw new NotSupportedException();
            }
        }

        public static void WriteItem(object o, WriteContext context)
        {
            if (o == null)
                throw new NotImplementedException();

            if (o is bool)
            {
                using (var c = context.Write("bool"))
                {
                    
                    c.WriteString(GetXmlBooleanString((bool) o));
                }
                return;
            }
            if (o is float)
            {
                using (var c = context.Write("r4"))
                {
                    c.WriteString(((float)o).ToString(CultureInfo.InvariantCulture.NumberFormat));
                }
                return;
            }
            if (o is double)
            {
                using (var c = context.Write("r8"))
                {
                    c.WriteString(((double)o).ToString(CultureInfo.InvariantCulture.NumberFormat));
                }
                return;
            }
            string name = GetTypeName(o);
            if (name != null)
            {
                using (var c = context.Write(name))
                {
                    c.WriteString(o.ToString());
                }
                return;

            }
            if (o is IOfficeXmlSerializable)
            {
                context.WriteElement((IOfficeXmlSerializable) o);
                return;
            }
            throw new NotImplementedException();
        }

        internal static string GetXmlBooleanString(bool o)
        {
            return o ? "true" : "false";
        }

        private static string GetTypeName(object o)
        {
            if (o is string)
                return "lpstr";
            if (o is byte)
            {
                return "ui1";
            }
            if (o is sbyte)
                return "i1";
            if (o is short)
                return "i2";
            if (o is ushort)
                return "ui2";
            if (o is int)
                return "i4";
            if (o is uint)
                return "ui4";
            if (o is long)
                return "ui8";
            if (o is ulong)
                return "ui8";
            return null;
        }
    }

    class Vector: IOfficeXmlSerializable
    {
        List<object> _items = new List<object>();
        private VectorBaseType _baseType;

        public void ReadXml(ReadContext context)
        {
            using (var c = context.Read(OfficeConstants.VariantNamespace + "vector"))
            {
                int size = c.GetInteger("size");
                _baseType = c.GetEnum<VectorBaseType>("baseType");
                while (c.ReaderLocalName != null)
                {
                    _items.Add(Variant.ReadItem(c));
                }
            }

        }


        public void WriteXml(WriteContext context)
        {
            using (var c = context.Write(OfficeConstants.VariantNamespace + "vector"))
            {
                c.SetInteger("size", _items.Count); 
                c.SetEnum("baseType", _baseType);
                foreach (var o in _items)
                {
                    Variant.WriteItem(o, c);
                }
                
            }
        }
    }
}